#pragma once

#include "znx_http_conf.h"
#include "comm/znx_hash_tab.h"
#include "comm/znx_slru.h"
#include "comm/znx_time.h"


typedef struct {
    znx_hash_node_t             node;
    znx_str_t                   host;
    int64_t                     version;
} znx_http_site_meta_item_t;


static inline int
znx_http_site_meta_item_cmp(znx_hash_node_t *a, znx_hash_node_t *b)
{
    znx_http_site_meta_item_t   *item_a = (znx_http_site_meta_item_t *)a;
    znx_http_site_meta_item_t   *item_b = (znx_http_site_meta_item_t *)b;

    if (item_a->host.len > item_b->host.len) {
        return 1;
    }

    if (item_a->host.len < item_b->host.len) {
        return -1;
    }

    return znx_strncmp(item_a->host.data, item_b->host.data, item_a->host.len);
}


typedef struct {
    znx_rwlock_t                rwlock;
    znx_hash_tab_t              *meta;
} znx_http_site_mgr_meta_t;


typedef struct {
    znx_spinlock_t              lock;
    znx_slru_t                  *slru;
} znx_http_site_mgr_t;


static inline void
znx_http_site_conf_free_handle(void *data)
{
    znx_http_site_conf_free((znx_http_site_conf_t *)data);
}


static inline int
znx_http_site_conf_cmp_handle(void *data_a, void *data_b)
{
    znx_http_site_conf_t    *site_conf_a = data_a;
    znx_http_site_conf_t    *site_conf_b = data_b;

    if (site_conf_a->crc > site_conf_b->crc) {
        return 1;
    }

    if (site_conf_a->crc < site_conf_b->crc) {
        return -1;
    }

    if (site_conf_a->server_name.len > site_conf_b->server_name.len) {
        return 1;
    }

    if (site_conf_a->server_name.len < site_conf_b->server_name.len) {
        return -1;
    }

    return znx_strncmp(site_conf_a->server_name.data,
        site_conf_b->server_name.data,
        site_conf_a->server_name.len);
}


void znx_http_site_mgr_init();

void znx_http_site_mgr_destroy();

void znx_http_site_meta_insert(znx_str_t *host, int64_t version);

znx_bool_t znx_http_site_meta_lookup(znx_str_t *host, int64_t *version);

void znx_http_site_meta_delete(znx_str_t *host);

void znx_http_site_insert(znx_http_site_conf_t *site_conf);

void znx_http_site_mgr_delete(znx_str_t *host);


// After use, you must call znx_http_site_conf_free release it.
// We will first lookup the meta table.
// Secondly if the conf not exists, we will load it.
znx_http_site_conf_t *znx_http_site_mgr_lookup(znx_str_t *host,
    znx_bool_t *not_found, char **err);


// After use, you must call znx_http_addr_site_conf_free release it.
znx_http_addr_site_conf_t *znx_http_addr_site_lookup(znx_str_t *host,
    znx_address_t *listen_address, znx_bool_t *not_found, char **err);


static inline void
znx_http_addr_site_conf_free(znx_http_addr_site_conf_t *addr_site)
{
    znx_http_site_conf_free(addr_site->site_conf);
}

